package com.hyts.agent.exec;
import com.hyts.agent.auto.config.DefaultAgentLoggerConfig;
import com.hyts.agent.auto.logger.jul.DefaultAgentLogger;
import com.hyts.agent.auto.transform.DefaultClassTransformService;
import com.hyts.agent.base.context.AgentInternalContext;
import com.hyts.agent.base.context.AgentMetadataContext;
import com.hyts.agent.base.error.AgentException;
import com.hyts.agent.base.logger.AgentLogger;
import com.hyts.agent.filter.AgentAspectInterceptor;
import com.hyts.agent.logger.AgentLogManager;
import com.hyts.agent.spi.args.AgentInitializeProcessArgs;
import com.hyts.agent.spi.args.AgentreloadProcessArgs;
import com.hyts.agent.spi.transform.AgentClassTransform;
import com.hyts.classcode.enhance.bytebuddy.factory.ByteBuddyAgentFactory;
import com.hyts.classcode.enhance.bytebuddy.listener.ClassAgentListener;
import com.hyts.guava.object.Objects;

import java.lang.instrument.Instrumentation;
import java.text.MessageFormat;
import java.util.Iterator;
import java.util.ServiceLoader;

/**
 * project-name:coffice-toolbox
 * package-name:com.hyts.agent.spi
 * author:Libo/Alex
 * create-date:2019-06-29 21:09
 * copyright:libo-hyts-github
 * email:libo2dev@aliyun.com
 * description:此类主要用于: agent探针操作-spi操作帮助类
 */
public class AgentComponentExecutor {

    /**
     * 操作日志
     */
    private AgentLogger logger = AgentLogManager.getAgentLogger(AgentComponentExecutor.class);
    /**
     * 读取执行spi 参数级别的初始化接口实现类
     */
    public void executeInitializeArgs(String args){
        ServiceLoader<AgentInitializeProcessArgs> agentInitializeProcessArgs =
                ServiceLoader.load(AgentInitializeProcessArgs.class);
        Iterator<AgentInitializeProcessArgs> agentInitializeProcessArgsIterator = agentInitializeProcessArgs.iterator();
        logger.info("读取spi配置读取-初始化参数配置 - AgentInitializeProcessArgs 接口实现类");
        try {
            while(agentInitializeProcessArgsIterator.hasNext()){
                AgentInitializeProcessArgs agentInitializeProcessArgsApi =  agentInitializeProcessArgsIterator.next();
                logger.info("执行获取读取初始化参数接口实现类:"+agentInitializeProcessArgsApi.getClass().getName());
                agentInitializeProcessArgsApi.processArgs(args);
                logger.info("完成执行获取读取初始化参数接口实现类");
            }
        } catch (Exception e) {
            throw new AgentException("执行获取初始化参数接口实现类失败！",e);
        }
    }

    /**
     * 读取执行spi 参数级别的重新加载接口实现类
     * @param args
     */
    public void executeReloadArgs(String args){
        ServiceLoader<AgentreloadProcessArgs> agentReloadProcessArgs = ServiceLoader.load(AgentreloadProcessArgs.class);
        Iterator<AgentreloadProcessArgs> agentReloadProcessArgsIterator = agentReloadProcessArgs.iterator();
        logger.info("读取spi配置读取-重新加载参数配置 - AgentreloadProcessArgs 接口实现类");
        try {
            while(agentReloadProcessArgsIterator.hasNext()){
                AgentreloadProcessArgs agentreloadProcessArgs1 =  agentReloadProcessArgsIterator.next();
                logger.info("执行获取读取重新加载参数接口实现类:"+agentreloadProcessArgs1.getClass().getName());
                agentreloadProcessArgs1.processArgs(args);
                logger.info("完成执行获取读取重新加载参数接口实现类");
            }
        } catch (Exception e) {
            throw new AgentException("执行获取重新加载参数接口实现类失败！",e);
        }
    }

    /**
     * 读取执行spi class文件转换器服务功能
     * @param instrumentation
     */
    public void executeClassTransformByJavasist(Instrumentation instrumentation){
        logger.info("开始启动执行agent探针服务-premain操作服务 - javasisit");
        ServiceLoader<AgentClassTransform> classTransformServiceList = ServiceLoader.load(AgentClassTransform.class);
        Iterator<AgentClassTransform> iterator = classTransformServiceList.iterator();
        logger.info("开始执行字节码增强工作 - javasisit");
        AgentMetadataContext.getClassTransFormNum().incrementAndGet();
        while(iterator.hasNext()){
            AgentClassTransform spiTransformService = iterator.next();
            if(spiTransformService.getClass().getName().equals(DefaultClassTransformService.class.getName())){
                logger.warn("遇到相关系统默认的com.hyts.agent.core.DefaultSpiTransformService直接被忽略!");
            }else {
                instrumentation.addTransformer(spiTransformService, spiTransformService.isRetransform());
            }
        }
        AgentMetadataContext.setAllLoadedClasses(instrumentation.getAllLoadedClasses());
        instrumentation.addTransformer(new DefaultClassTransformService());
        logger.info("完成启动执行agent探针服务-premain操作服务 javasisit");
    }

    /**
     * 读取执行spi class文件转换器服务功能 - bytebuddy
     * @param instrumentation
     */
    public void executeClassTransformeByBuddy(Instrumentation instrumentation){
        //构建探针agent builder构建器
        logger.info("开始启动执行agent探针服务-premain操作服务 - buddy");
        AgentMetadataContext.getClassTransFormNum().incrementAndGet();
        AgentMetadataContext.setAllLoadedClasses(instrumentation.getAllLoadedClasses());
        ServiceLoader<AgentAspectInterceptor> agentAspectInterceptors = ServiceLoader.load(AgentAspectInterceptor.class);
        Iterator<AgentAspectInterceptor> iterator = agentAspectInterceptors.iterator();
        AgentMetadataContext.getClassTransFormNum().incrementAndGet();
        while(iterator.hasNext()){
            AgentAspectInterceptor agentAspectInterceptor = iterator.next();
            logger.info(MessageFormat.format("开始执行字节码增强工作 - bytebuddy{0}",
                    agentAspectInterceptor.getClass().getName()));
            ByteBuddyAgentFactory.create(instrumentation,agentAspectInterceptor, new ClassAgentListener());
        }
        logger.info("完成启动执行agent探针服务-premain操作服务 bytebuddy");
    }

    /**
     * 读取执行操作agent探针服务加载全局日志功能
     * 动态去读取外部项目得日志注入器或者内部默认得日志注入器
     */
      public static void executeAgentLogger(){
        ServiceLoader<AgentLogger> classTransformServiceList = ServiceLoader.load(AgentLogger.class);
        // 循环遍历以及选择相关得日志服务插件
        Integer maxWeight = null;
        for (AgentLogger agentLogger : classTransformServiceList) {
            System.out.printf("%s读取到了日志插件扩展类:%s%s%n", DefaultAgentLoggerConfig.DEFAULT_LOGGER_PREFIX, agentLogger.getClass().getName(), DefaultAgentLoggerConfig.DEFAULT_LOGGER_SUBFIX);
            // 读取则直接将juilogger置为 false
            if(Objects.nonNull(maxWeight)){
              if(agentLogger.order() < maxWeight.intValue()){
                  maxWeight = agentLogger.order();
                  // 以及设置当前得agentLogger为读取得服务
                  AgentInternalContext.agentLogger = agentLogger;
              }
            }else{
                maxWeight = agentLogger.order();
                // 以及设置当前得agentLogger为读取得服务
                AgentInternalContext.agentLogger = agentLogger;
            }
            AgentInternalContext.juiLogger = false;
        }
         //AgentInternalContext.agentLogger =
        System.out.printf("%s最终选择:%s为探针日志服务组件%s%n", DefaultAgentLoggerConfig.DEFAULT_LOGGER_PREFIX,
                AgentInternalContext.juiLogger? DefaultAgentLogger.class.getName() :AgentInternalContext.agentLogger.getClass().getName(), DefaultAgentLoggerConfig.DEFAULT_LOGGER_SUBFIX);
    }

}
